package java6.io;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;

public class UtilLoser implements Constantes {

    private Map<Integer, Object> linea = new TreeMap<>();
    public static int tipoLog = 0;
    public static boolean pintaLog;
    private StringBuilder stb = new StringBuilder();
    private int[] c0 = null;
    private int[] cx = null;
    private int[] cn = null;
    private int[] ck = null;
    private int[] cj = null;

    private void inicializaOrdenadores() {
        if (c0 == null) {
            c0 = new int[]{0, 20, 40, 60, 80};
            cx = new int[]{100, 120, 140, 160, 180};
            cn = new int[]{200, 300, 400, 500, 600};
            ck = new int[]{700, 750};
            cj = new int[]{800, 820, 840, 860};
        } else {
            c0[0] = 0;
            c0[1] = 20;
            c0[2] = 40;
            c0[3] = 60;
            c0[4] = 80;
            cx[0] = 100;
            cx[1] = 120;
            cx[2] = 140;
            cx[3] = 160;
            cx[4] = 180;
            cn[0] = 200;
            cn[1] = 300;
            cn[2] = 400;
            cn[3] = 500;
            cn[4] = 600;
            ck[0] = 700;
            ck[1] = 750;
            cj[0] = 800;
            cj[1] = 820;
            cj[2] = 840;
            cj[3] = 860;
        }
    }

    public int[] obtenerValoresPiezaXColor(int color) {
        switch (color) {
            case white:
                return new int[]{PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING};
            case black:
                return new int[]{pawn, knight, bishop, rook, queen, king};
        }
        return null;
    }

    public String imprimirTablero(int[] posiciones, boolean estavolteado) {

        StringBuilder tablero = new StringBuilder();
        String aux = "";
        int ficha, ind;

        for (int i = 0; i < 64; i++) {
            ind = estavolteado ? 63 - i : i;

            ficha = posiciones[ind];

            switch (ficha) {
                case vacio:
                    aux += "" + "|\t";
                    break;
                case PAWN:
                case pawn:
                    aux += (ficha == PAWN ? "P0" : "p1") + "|\t";
                    break;
                case KNIGHT:
                case knight:
                    aux += (ficha == KNIGHT ? "N" : "n") + "|\t";
                    break;
                case BISHOP:
                case bishop:
                    aux += (ficha == BISHOP ? "B" : "b") + "|\t";
                    break;
                case ROOK:
                case rook:
                    aux += (ficha == ROOK ? "R" : "r") + "|\t";
                    break;
                case QUEEN:
                case queen:
                    aux += (ficha == QUEEN ? "Q" : "q") + "|\t";
                    break;
                case KING:
                case king:
                    aux += (ficha == KING ? "K" : "k") + "|\t";
                    break;
            }
            if (estavolteado) {
                if (ind % 8 == 0) {
                    tablero.insert(0, (ind / 8 + 1) + "\t" + aux + "\n");
                    aux = "";
                }
            } else {
                if (ind != 0 && (ind + 1) % 8 == 0) {
                    tablero.insert(0, (ind / 8 + 1) + "\t" + aux + "\n");
                    aux = "";
                }
            }
        }

        if (estavolteado) {
            tablero.append("\t h \t g \t f \t e \t d \t c \t b \t a");
        } else {
            tablero.append("\t a \t b \t c \t d \t e \t f \t g \t h");
        }

        return tablero.toString();
    }

    public int esJaque(int[] amenazas) {
        int pos_jaque = -1;//-1=no hay jaque, 100=doble jaque, otro=pos jaque

        for (int i = 0; i < amenazas.length; i++) {
            if (amenazas[i] > 99) {
                if (pos_jaque == -1) {
                    pos_jaque = amenazas[i] - 100;
                } else {
                    pos_jaque = 100;
                    break;
                }
            }
        }
        return pos_jaque;
    }

    public int esJaque(int[] amenazas, int pos_king) {
        int pos_jaque = -1;//-1=no hay jaque, 100=doble jaque, otro=pos jaque

        for (int i = 0; i < amenazas.length; i++) {
            if (amenazas[i] == pos_king) {
                if (pos_jaque == -1) {
                    pos_jaque = amenazas[i];
                } else {
                    pos_jaque = 100;
                    break;
                }
            }
        }
        return pos_jaque;
    }

    public int devuelvePosicionRey(int[] tablero, int color) {

        int bking = color == white ? KING : king;

        for (int j = 0; j < 64; j++) {
            if (tablero[j] == bking) {
                return j;
            }
        }

        return -1;
    }

    public String imprimirJugadas(List< int[]> jugadas) {

        StringBuilder stb = new StringBuilder();

        for (int[] j : jugadas) {
            stb.append(this.imprimirJugada(j)).append(",");
        }

        return stb.toString();
    }

    public String imprimirJugada(int[] j) {

        String strj = this.pos1(j[1]) + this.pos1(j[2]);

        if (j.length > 3) {
            switch (j[3]) {
                case KNIGHT:
                case knight:
                    strj += sKNIGHT;
                    break;
                case BISHOP:
                case bishop:
                    strj += sBISHOP;
                    break;
                case ROOK:
                case rook:
                    strj += sROOK;
                    break;
                case QUEEN:
                case queen:
                    strj += sQUEEN;
                    break;
            }
        }

        return strj;
    }

    public boolean enFila(int pos, int pos_king) {
        int f;
        for (int i = 0; i < 8; i++) {
            f = i * 8;
            if (pos >= f && pos < f + 8
                    && pos_king >= f && pos_king < f + 8) {
                return true;
            }
        }
        return false;
    }

    public boolean enColumna(int pos, int pos_king) {
        if (Math.abs(pos - pos_king) % 8 == 0) {
            return true;
        }
        return false;
    }

    public int[] convertirListtoArray(List<Integer> amenazas) {
        int[] array = new int[amenazas.size()];

        for (int i = 0; i < amenazas.size(); i++) {
            array[i] = amenazas.get(i);
        }

        return array;
    }

    public boolean siArrayContiene(int[] amenazas, int val) {
        for (int j = 1; j < amenazas[0]; j++) {
            if (amenazas[j] == val) {
                return true;
            }
        }
        return false;
    }

    private String pos1(int pos) {
        String str;

        if (pos < 8) {
            str = pos2(pos) + 1;
        } else {
            str = pos2(pos % 8) + (pos / 8 + 1);
        }

        return str;
    }

    private String pos2(int pos) {
        switch (pos) {
            case 0:
                return "a";
            case 1:
                return "b";
            case 2:
                return "c";
            case 3:
                return "d";
            case 4:
                return "e";
            case 5:
                return "f";
            case 6:
                return "g";
            case 7:
                return "h";
        }
        return "x";
    }

    public boolean estanEnDiagonal(int x, int y) {

        int factor = 1;
        int val;
        boolean a7 = true,
                b7 = true,
                a9 = true,
                b9 = true;
        do {
            if (a7) {
                val = x - (7 * factor);
                if (val % 8 > 0) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    a7 = false;
                }
            }
            if (b7) {
                val = x + (7 * factor);
                if (val < 64 && val % 8 < 7) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    b7 = false;
                }
            }
            if (a9) {
                val = x - (9 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    a9 = false;
                }
            }
            if (b9) {
                val = x + (9 * factor);
                if (val < 64 && val % 8 > 0) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    b9 = false;
                }
            }
            factor++;
        } while ((a7 || b7 || a9 || b9) && factor < 8);

        return false;
    }

    public int[] ingresarJugada(int[] tablero, int[] jugada, boolean esCopia) {

        int[] _tablero;
        int ficha = jugada[0];
        int ini = jugada[1];
        int fin = jugada[2];
        int prom = jugada.length > 3 ? jugada[3] : 0;

        if (esCopia) {
            _tablero = new int[64];
            System.arraycopy(tablero, 0, _tablero, 0, 64);
        } else {
            _tablero = tablero;
        }

        if (ficha == pawn || ficha == PAWN) {
            if (fin > ini) {
                if (ini >= 32 && ini <= 39 && ini + 8 != fin && _tablero[fin] == vacio) {
                    _tablero[(fin - 8)] = vacio;
                }
            } else if (ini >= 24 && ini <= 31 && ini - 8 != fin && _tablero[fin] == vacio) {
                _tablero[(fin + 8)] = vacio;
            }
        } else if ((ficha == king || ficha == KING) && (ini == 4 || ini == 60)) {
            switch (fin) {
                case 2:
                    _tablero[3] = ROOK;
                    _tablero[0] = vacio;
                    break;
                case 6:
                    _tablero[5] = ROOK;
                    _tablero[7] = vacio;
                    break;
                case 58:
                    _tablero[59] = rook;
                    _tablero[56] = vacio;
                    break;
                case 62:
                    _tablero[61] = rook;
                    _tablero[63] = vacio;
            }
        }

        _tablero[fin] = (prom != 0 ? prom : _tablero[ini]);
        _tablero[ini] = vacio;

        return _tablero;
    }

    public boolean[] verificarEnroques(int ficha, int ini, boolean[] oo, boolean isWhite, boolean esCopia) {

        boolean[] enroques = null;

        if (oo[isWhite ? 0 : 2] || oo[isWhite ? 1 : 3]) {
            if (esCopia) {
                enroques = new boolean[4];
                System.arraycopy(oo, 0, enroques, 0, 4);
            } else {
                enroques = oo;
            }

            if (ficha == king || ficha == KING) {
                enroques[isWhite ? 0 : 2] = false;
                enroques[isWhite ? 1 : 3] = false;
            } else if (ficha == rook || ficha == ROOK) {
                switch (ini) {
                    case 0:
                    case 56:
                        enroques[isWhite ? 1 : 3] = false;
                        break;
                    case 7:
                    case 63:
                        enroques[isWhite ? 0 : 2] = false;
                        break;
                }
            }
        }

        return enroques == null ? oo : enroques;
    }

    public String convertirJugada(String j) {

        char[] c = j.toCharArray();

        return convnum(new char[]{c[0], c[1]}) + "," + convnum(new char[]{c[2], c[3]});
    }

    public int convnum(char[] c) {
        switch (c[0]) {
            case 'a':
                return 8 * (Character.getNumericValue(c[1]) - 1);
            case 'b':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 1;
            case 'c':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 2;
            case 'd':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 3;
            case 'e':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 4;
            case 'f':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 5;
            case 'g':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 6;
            case 'h':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 7;
        }
        return -1;
    }

    public int valorarTableroDefensivo(int[] t, int color) {
        int valor = 0;
        int peones = 0;
        int ficha;

        if (color == white) {
            for (int i = 0; i < 64; i++) {
                ficha = t[i];
                if (ficha < 0) {
                    valor = valor + 1;
                    if (ficha == PAWN) {
                        peones = peones + 1;
                    }
                }
            }
        } else {
            for (int i = 0; i < 64; i++) {
                ficha = t[i];
                if (ficha > 0) {
                    valor = valor + 1;
                    if (ficha == pawn) {
                        peones = peones + 1;
                    }
                }
            }
        }

        //validando que quede al menos un peón
        if (peones == 0) {
            valor = -1;
        }

        return valor;
    }

    public int valorarTableroAgresivo(int[] t, int color) {
        int valor = 0;

        if (color == white) {
            for (int i = 0; i < 64; i++) {
                if (t[i] < 0) {
                    valor++;
                }
            }
        } else {
            for (int i = 0; i < 64; i++) {
                if (t[i] > 0) {
                    valor++;
                }
            }
        }

        return valor;
    }

    public boolean valorarTableroCompleto(int[] t) {
        int w = 0;
        int b = 0;
        int ficha;

        for (int i = 0; i < 64; i++) {
            ficha = t[i];
            if (ficha < 0) {
                w++;
            } else if (ficha > 0) {
                b++;
            }
        }

        return w < 10 || b < 10 ? true : false;
    }

    public List< int[]> ordenarMisJugadas(Jugadas jugadas, int[] tablero) {

        Map<Integer, int[]> nuevasJugadas = new TreeMap<>();
        List< int[]> peones = new ArrayList<>();
        int ficha;
        int c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0;
        boolean esObligatorio = jugadas.isEsObligatorio();
        int fin;

        if (esObligatorio) {
            for (int[] j : jugadas.getJugadas()) {
                fin = j[2];
                switch (tablero[fin]) {
                    case vacio:
                    case PAWN:
                    case pawn:
                        nuevasJugadas.put(c1 + 40, j);
                        break;
                    case KNIGHT:
                    case knight:
                        nuevasJugadas.put(c1 + 30, j);
                        break;
                    case BISHOP:
                    case bishop:
                        nuevasJugadas.put(c1 + 20, j);
                        break;
                    case ROOK:
                    case rook:
                        nuevasJugadas.put(c1 + 10, j);
                        break;
                    case QUEEN:
                    case queen:
                        nuevasJugadas.put(c1 + 0, j);
                        break;
                }
                c1++;
            }
        } else {
            for (int[] j : jugadas.getJugadas()) {
                ficha = j[0];

                switch (ficha) {
                    case PAWN:
                    case pawn:
                        peones.add(j);
                        break;
                    case KNIGHT:
                    case knight:
                        nuevasJugadas.put(c2 + 100, j);
                        c2++;
                        break;
                    case KING:
                    case king:
                        nuevasJugadas.put(c3 + 200, j);
                        c3++;
                        break;
                    case BISHOP:
                    case bishop:
                        nuevasJugadas.put(c4 + 300, j);
                        c4++;
                        break;
                    case QUEEN:
                    case queen:
                        nuevasJugadas.put(c5 + 400, j);
                        c5++;
                        break;
                    case ROOK:
                    case rook:
                        nuevasJugadas.put(c6 + 500, j);
                        c6++;
                        break;
                }
            }

            if (!peones.isEmpty()) {
                Collections.shuffle(peones, new Random());
                for (int[] p : peones) {
                    nuevasJugadas.put(c1, p);
                    c1++;
                }
            }
        }

        return new ArrayList<>(nuevasJugadas.values());
    }

    public int[] obtenerJugadadeString(String in, int[] t) {
        int[] j = new int[4];
        char[] c = in.toCharArray();

        j[1] = this.convnum(new char[]{c[0], c[1]});
        j[2] = this.convnum(new char[]{c[2], c[3]});

        j[0] = t[j[1]];

        if (c.length > 4) {
            switch (c[4]) {
                case 'N':
                case 'n':
                    j[3] = j[0] < 0 ? KNIGHT : knight;
                    break;
                case 'B':
                case 'b':
                    j[3] = j[0] < 0 ? BISHOP : bishop;
                    break;
                case 'R':
                case 'r':
                    j[3] = j[0] < 0 ? ROOK : rook;
                    break;
                case 'Q':
                case 'q':
                    j[3] = j[0] < 0 ? QUEEN : queen;
                    break;
            }
        }

        return j;
    }

    public String obtenerNotacionFEN(int[] tablero) {

        stb.delete(0, stb.length());
        int i;
        int h = 0;
        int ficha;

        for (i = 0; i < 64; i++) {
            ficha = tablero[i];

            if (ficha == vacio) {
                h++;
            } else {
                if (h == 0) {
                    stb.append(devolverPieza(ficha));
                } else {
                    stb.append(h).append(devolverPieza(ficha));
                    h = 0;
                }
            }
        }

        return stb.toString();
    }

    private String devolverPieza(int ficha) {
        switch (ficha) {
            case PAWN:
                return sPAWN;
            case pawn:
                return spawn;
            case BISHOP:
                return sBISHOP;
            case bishop:
                return sbishop;
            case KNIGHT:
                return sKNIGHT;
            case knight:
                return sknight;
            case ROOK:
                return sROOK;
            case rook:
                return srook;
            case QUEEN:
                return sQUEEN;
            case queen:
                return squeen;
            default: //king
                return ficha == KING ? sKING : sking;
        }
    }

    public void ingresarJugadaLog(int pos, int[] j, boolean b) {
        linea.put(pos, j);
        if (tipoLog != 0 && b) {
            pintaLog = true;
        }
    }

    public void mostrarLog(int limite, String bol) {
        linea.put(limite + 1, bol);
        if (tipoLog != 0) {
            switch (tipoLog) {
                case 1:
                    linea.put(limite + 1, bol);
                    break;
                case 2:
                    if (bol.equals("true") || bol.equals("xtrue")) {
                        this.imprimirLinea(limite, bol, 2);
                    } else {
                        if (pintaLog) {
                            this.imprimirLinea(limite, bol, 2);
                            pintaLog = false;
                        }
                    }
                    break;
            }
        }
    }

    public void mostrarLog2() {
        if (tipoLog != 0) {
            if (tipoLog == 1) {
                this.imprimirLinea(-1, "true", 1);
            }
            linea.clear();
        }
    }

    private void imprimirLinea(int posi, String esValido, int tipo) {

        Object o;
        int[] j;
        String s;
        Set<Integer> keyset;

        switch (tipo) {
            case 1:
                keyset = linea.keySet();
                for (int k : keyset) {
                    o = linea.get(k);

                    if (o instanceof int[]) {
                        j = (int[]) o;
                        System.out.print(this.imprimirJugada(j) + ",");
                    } else {
                        s = (String) o;
                        System.out.print(s + "\n");
                        break;
                    }
                }
                break;
            case 2:
                int cnt = 0;
                keyset = linea.keySet();
                for (int k : keyset) {
                    o = linea.get(k);

                    if (o instanceof int[]) {
                        j = (int[]) o;
                        if (cnt < posi + 1) {
                            System.out.print((cnt % 2 == 0 ? "_" : "") + this.imprimirJugada(j) + ",");
                        } else {
                            break;
                        }
                        cnt++;
                    } else {
                        break;
                    }
                }
                System.out.print(esValido + "\n");
                break;
        }
    }

    public List< int[]> ordenarCapturas(List< int[]> capturas, int[] amenazas) {
        Map<Integer, int[]> nuevasJugadas = new TreeMap<>();
        int ficha;
        int c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0;

        for (int[] j : capturas) {
            ficha = j[0];

            switch (ficha) {
                case QUEEN:
                case queen:
                    if (c1 == 0) {
                        nuevasJugadas.put(c1 + 50, j);
                    } else if (this.siArrayContiene(amenazas, j[2])) {
                        nuevasJugadas.put(c1, j);
                    } else {
                        nuevasJugadas.put(c1 + 50, j);
                    }
                    c1++;
                    break;
                case BISHOP:
                case bishop:
                    if (c2 == 0) {
                        nuevasJugadas.put(c2 + 150, j);
                    } else if (this.siArrayContiene(amenazas, j[2])) {
                        nuevasJugadas.put(c2 + 100, j);
                    } else {
                        nuevasJugadas.put(c2 + 150, j);
                    }
                    c2++;
                    break;
                case ROOK:
                case rook:
                    if (c3 == 0) {
                        nuevasJugadas.put(c3 + 250, j);
                    } else if (this.siArrayContiene(amenazas, j[2])) {
                        nuevasJugadas.put(c3 + 200, j);
                    } else {
                        nuevasJugadas.put(c3 + 250, j);
                    }
                    c3++;
                    break;
                case PAWN:
                case pawn:
                    if (c4 == 0) {
                        nuevasJugadas.put(c4 + 350, j);
                    } else if (this.siArrayContiene(amenazas, j[2])) {
                        nuevasJugadas.put(c4 + 300, j);
                    } else {
                        nuevasJugadas.put(c4 + 350, j);
                    }
                    c4++;
                    break;
                case KNIGHT:
                case knight:
                    if (c5 == 0) {
                        nuevasJugadas.put(c5 + 450, j);
                    } else if (this.siArrayContiene(amenazas, j[2])) {
                        nuevasJugadas.put(c5 + 400, j);
                    } else {
                        nuevasJugadas.put(c5 + 450, j);
                    }
                    c5++;
                    break;
                case KING:
                case king:
                    nuevasJugadas.put(c6 + 500, j);
                    c6++;
                    break;
            }
        }

        return new ArrayList<>(nuevasJugadas.values());
    }

    public List< int[]> ordenarJaque(List< int[]> movimientos, int[] tablero, int jugador) {
        Map<Integer, int[]> nuevasOrden = new TreeMap<>();
        int ficha;
        int c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0;

        for (int[] j : movimientos) {
            ficha = j[0];

            switch (ficha) {
                case QUEEN:
                case queen:
                    nuevasOrden.put(c1, j);
                    c1++;
                    break;
                case BISHOP:
                case bishop:
                    nuevasOrden.put(c2 + 100, j);
                    c2++;
                    break;
                case ROOK:
                case rook:
                    nuevasOrden.put(c3 + 200, j);
                    c3++;
                    break;
                case PAWN:
                case pawn:
                    nuevasOrden.put(c4 + 300, j);
                    c4++;
                    break;
                case KNIGHT:
                case knight:
                    nuevasOrden.put(c5 + 400, j);
                    c5++;
                    break;
                case KING:
                case king:
                    if (this.verificarOrdenRey(tablero, jugador, j[2])) {
                        nuevasOrden.put(c6 + 500, j);
                    } else {
                        nuevasOrden.put(c6 + 550, j);
                    }
                    c6++;
                    break;
            }
        }

        return new ArrayList<>(nuevasOrden.values());
    }

    public void pintarjugadas(List< int[]> l, int tipo) {
        if (tipoLog == 2) {
            if (tipo == 0) {
                System.out.println("mis_jugadas: for [" + this.imprimirJugadas(l) + "]");
            } else {
                System.out.println("for [" + this.imprimirJugadas(l) + "]");
            }
        }
    }

    private boolean verificarOrdenRey(int[] tablero, int jugador, int pos) {
        int val;

        if (jugador == white) {
            val = pos - 1;
            if (val >= 0 && val % 8 < 7 && tablero[val] < vacio) {
                return false;
            }
            val = pos + 1;
            if (val % 8 > 0 && tablero[val] < vacio) {
                return false;
            }
            val = pos - 7;
            if (val % 8 > 0 && tablero[val] < vacio) {
                return false;
            }
            val = pos + 7;
            if (val < 64 && val % 8 < 7 && tablero[val] < vacio) {
                return false;
            }
            val = pos - 8;
            if (val >= 0 && tablero[val] < vacio) {
                return false;
            }
            val = pos + 8;
            if (val < 64 && tablero[val] < vacio) {
                return false;
            }
            val = pos - 9;
            if (val >= 0 && val % 8 < 7 && tablero[val] < vacio) {
                return false;
            }
            val = pos + 9;
            if (val < 64 && val % 8 > 0 && tablero[val] < vacio) {
                return false;
            }
        } else {
            val = pos - 1;
            if (val >= 0 && val % 8 < 7 && tablero[val] > vacio) {
                return false;
            }
            val = pos + 1;
            if (val % 8 > 0 && tablero[val] > vacio) {
                return false;
            }
            val = pos - 7;
            if (val % 8 > 0 && tablero[val] > vacio) {
                return false;
            }
            val = pos + 7;
            if (val < 64 && val % 8 < 7 && tablero[val] > vacio) {
                return false;
            }
            val = pos - 8;
            if (val >= 0 && tablero[val] > vacio) {
                return false;
            }
            val = pos + 8;
            if (val < 64 && tablero[val] > vacio) {
                return false;
            }
            val = pos - 9;
            if (val >= 0 && val % 8 < 7 && tablero[val] > vacio) {
                return false;
            }
            val = pos + 9;
            if (val < 64 && val % 8 > 0 && tablero[val] > vacio) {
                return false;
            }
        }
        return true;
    }

    public List<int[]> ordenarJugadasLocal(List< int[]> jugadas, int[] tablero,
            int[] amenazas, int[] amenazasrival, int jugador, int pos_king) {

        int size = jugadas.size();
        int[] nuevoOrden = new int[size];
        List<int[]> ordenado = new ArrayList(size);
        int cnt = 0;
        int ficha, fin;

        this.inicializaOrdenadores();

        for (int[] j : jugadas) {
            ficha = j[0];
            fin = j[2];

            switch (ficha) {
                case QUEEN:
                case queen:
                    if (this.siArrayContiene(amenazasrival, fin)) {
                        if (!this.siArrayContieneDoble(amenazas, fin)) {
                            nuevoOrden[cnt] = c0[0];
                            c0[0]++;
                        } else {
                            nuevoOrden[cnt] = cx[0];
                            cx[0]++;
                        }
                    } else {
                        if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                            nuevoOrden[cnt] = cj[0];
                            cj[0]++;
                        } else {
                            nuevoOrden[cnt] = cn[0];
                            cn[0]++;
                        }
                    }
                    break;
                case BISHOP:
                case bishop:
                    if (this.siArrayContiene(amenazasrival, fin)) {
                        if (!this.siArrayContieneDoble(amenazas, fin)) {
                            nuevoOrden[cnt] = c0[1];
                            c0[1]++;
                        } else {
                            nuevoOrden[cnt] = cx[1];
                            cx[1]++;
                        }
                    } else {
                        if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                            nuevoOrden[cnt] = cj[1];
                            cj[1]++;
                        } else {
                            nuevoOrden[cnt] = cn[1];
                            cn[1]++;
                        }
                    }
                    break;
                case ROOK:
                case rook:
                    if (this.siArrayContiene(amenazasrival, fin)) {
                        if (!this.siArrayContieneDoble(amenazas, fin)) {
                            nuevoOrden[cnt] = c0[2];
                            c0[2]++;
                        } else {
                            nuevoOrden[cnt] = cx[2];
                            cx[2]++;
                        }
                    } else {
                        if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                            nuevoOrden[cnt] = cj[2];
                            cj[2]++;
                        } else {
                            nuevoOrden[cnt] = cn[2];
                            cn[2]++;
                        }
                    }
                    break;
                case PAWN:
                case pawn:
                    if (this.siArrayContiene(amenazasrival, fin)) {
                        if (!this.siArrayContiene(amenazas, fin)) {
                            nuevoOrden[cnt] = c0[3];
                            c0[3]++;
                        } else {
                            nuevoOrden[cnt] = cx[3];
                            cx[3]++;
                        }
                    } else {
                        nuevoOrden[cnt] = cn[3];
                        cn[3]++;
                    }
                    break;
                case KNIGHT:
                case knight:
                    if (this.siArrayContiene(amenazasrival, fin)) {
                        if (!this.siArrayContieneDoble(amenazas, fin)) {
                            nuevoOrden[cnt] = c0[4];
                            c0[4]++;
                        } else {
                            nuevoOrden[cnt] = cx[4];
                            cx[4]++;
                        }
                    } else {
                        if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                            nuevoOrden[cnt] = cj[3];
                            cj[3]++;
                        } else {
                            nuevoOrden[cnt] = cn[4];
                            cn[4]++;
                        }
                    }
                    break;
                case KING:
                case king:
                    if (this.verificarOrdenRey(tablero, jugador, j[2])) {
                        nuevoOrden[cnt] = ck[0];
                        ck[0]++;
                    } else {
                        nuevoOrden[cnt] = ck[1];
                        ck[1]++;
                    }
                    break;
            }
            cnt++;
        }//ffor

        int _lim;
        int i, j;

        for (i = 0; i < 100; i = i + 20) {
            _lim = c0[i / 20] - i;
            for (j = 0; j < _lim; j++) {
                ordenado.add(jugadas.get(this.obtenerIndiceJugadaXOrden(nuevoOrden, i + j, size)));
            }
        }

        for (i = 100; i < 200; i = i + 20) {
            _lim = cx[(i - 100) / 20] - i;
            for (j = 0; j < _lim; j++) {
                ordenado.add(jugadas.get(this.obtenerIndiceJugadaXOrden(nuevoOrden, i + j, size)));
            }
        }

        for (i = 200; i < 700; i = i + 100) {
            _lim = cn[(i - 200) / 100] - i;
            for (j = 0; j < _lim; j++) {
                ordenado.add(jugadas.get(this.obtenerIndiceJugadaXOrden(nuevoOrden, i + j, size)));
            }
        }

        for (i = 700; i < 800; i = i + 50) {
            _lim = ck[(i - 700) / 50] - i;
            for (j = 0; j < _lim; j++) {
                ordenado.add(jugadas.get(this.obtenerIndiceJugadaXOrden(nuevoOrden, i + j, size)));
            }
        }

        for (i = 800; i < 880; i = i + 20) {
            _lim = cj[(i - 800) / 20] - i;
            for (j = 0; j < _lim; j++) {
                ordenado.add(jugadas.get(this.obtenerIndiceJugadaXOrden(nuevoOrden, i + j, size)));
            }
        }

        return ordenado;
    }

    private int obtenerIndiceJugadaXOrden(int[] nuevoOrden, int pos, int l) {
        for (int i = 0; i < l; i++) {
            if (nuevoOrden[i] == pos) {
                return i;
            }
        }
        return -1;
    }

    private boolean siArrayContieneDoble(int[] amenazas, int val) {
        int cnt = 0;
        for (int j = 1; j < amenazas[0]; j++) {
            if (amenazas[j] == val) {
                if (cnt == 1) {
                    return true;
                } else {
                    cnt++;
                }
            }
        }
        return false;
    }

    public boolean ingresarJugadayVerificarEnroques(int[] tablero, boolean[] enroques, int[] jugada, boolean isWhite) {

        int ficha = jugada[0];
        int ini = jugada[1];
        int fin = jugada[2];
        int prom = jugada.length > 3 ? jugada[3] : 0;

        if (ficha == pawn || ficha == PAWN) {
            if (fin > ini) {
                if (ini >= 32 && ini <= 39 && ini + 8 != fin && tablero[fin] == vacio) {
                    tablero[(fin - 8)] = vacio;
                }
            } else if (ini >= 24 && ini <= 31 && ini - 8 != fin && tablero[fin] == vacio) {
                tablero[(fin + 8)] = vacio;
            }
        } else if ((ficha == king || ficha == KING) && (ini == 4 || ini == 60)) {
            if (enroques[isWhite ? 0 : 2] || enroques[isWhite ? 1 : 3]) {
                enroques[isWhite ? 0 : 2] = false;
                enroques[isWhite ? 1 : 3] = false;
            }
            switch (fin) {
                case 2:
                    tablero[3] = ROOK;
                    tablero[0] = vacio;
                    break;
                case 6:
                    tablero[5] = ROOK;
                    tablero[7] = vacio;
                    break;
                case 58:
                    tablero[59] = rook;
                    tablero[56] = vacio;
                    break;
                case 62:
                    tablero[61] = rook;
                    tablero[63] = vacio;
                    break;
            }
        } else if (ficha == rook || ficha == ROOK) {
            if (enroques[isWhite ? 0 : 2] || enroques[isWhite ? 1 : 3]) {
                switch (ini) {
                    case 0:
                    case 56:
                        enroques[isWhite ? 1 : 3] = false;
                        break;
                    case 7:
                    case 63:
                        enroques[isWhite ? 0 : 2] = false;
                        break;
                }
            }
        }

        if (tablero[fin] == rook || tablero[fin] == ROOK) {
            if (enroques[!isWhite ? 0 : 2] || enroques[!isWhite ? 1 : 3]) {
                switch (ini) {
                    case 0:
                    case 56:
                        enroques[!isWhite ? 1 : 3] = false;
                        break;
                    case 7:
                    case 63:
                        enroques[!isWhite ? 0 : 2] = false;
                        break;
                }
            }
        }

        tablero[fin] = (prom != 0 ? prom : tablero[ini]);
        tablero[ini] = vacio;

        int cnt = 0;
        if (isWhite) {
            for (int i = 0; i < 64; i++) {
                if (tablero[i] > 0) {
                    if ((cnt = cnt + 1) > 1) {
                        break;
                    }
                }
            }
        } else {
            for (int i = 0; i < 64; i++) {
                if (tablero[i] < 0) {
                    if ((cnt = cnt + 1) > 1) {
                        break;
                    }
                }
            }
        }

        return cnt == 1 ? true : false;
    }

    public List< int[]> poblarcache() {
        List< int[]> temp = new ArrayList<>();
        int[] j;

        if (linea.size() > 1) {
            temp = new ArrayList<>();
            Object o;

            for (int k : linea.keySet()) {
                o = linea.get(k);

                if (o instanceof int[]) {
                    j = (int[]) o;
                    temp.add(j);
                } else {
                    break;
                }
            }
        }

        linea.clear();

        return temp;
    }

    public String mostrarCache(Object[] cachememory) {
        StringBuilder sb = new StringBuilder();
        List< int[]> l;
        int cnt = 1;

        for (Object o : cachememory) {
            if (o instanceof List) {
                l = (List< int[]>) o;
                sb.append(cnt).append(")");
                for (int[] j : l) {
                    sb.append(this.imprimirJugada(j)).append(",");
                }
                sb.append("\n");
                cnt++;
            }
        }

        return sb.toString();
    }

    public boolean verificarJaque(int[] tablero, int ficha, int pos,
            int pos_king) {

        switch (ficha) {
            case QUEEN:
            case queen:
                if (this.verificarJaqueDiagonal(tablero, pos, pos_king)) {
                    return true;
                }
                if (this.verificarJaqueHorizontalVertical(tablero, pos, pos_king)) {
                    return true;
                }
                break;
            case BISHOP:
            case bishop:
                if (this.verificarJaqueDiagonal(tablero, pos, pos_king)) {
                    return true;
                }
                break;
            case ROOK:
            case rook:
                if (this.verificarJaqueHorizontalVertical(tablero, pos, pos_king)) {
                    return true;
                }
                break;
            case KNIGHT:
            case knight:
                // +6 -6
                if ((pos < 56 && pos % 8 > 1) && pos + 6 == pos_king) {
                    return true;
                }
                if (pos > 7 && pos % 8 < 6 && pos - 6 == pos_king) {
                    return true;
                }
                // +10 -10
                if (pos < 56 && pos % 8 < 6 && pos + 10 == pos_king) {
                    return true;
                }
                if (pos > 7 && pos % 8 > 1 && pos - 10 == pos_king) {
                    return true;
                }
                // +15 -15
                if (pos < 48 && pos % 8 > 0 && pos + 15 == pos_king) {
                    return true;
                }
                if (pos > 15 && pos % 8 < 7 && pos - 15 == pos_king) {
                    return true;
                }
                // +17 -17
                if (pos < 48 && pos % 8 < 7 && pos + 17 == pos_king) {
                    return true;
                }
                if ((pos > 15 && pos % 8 > 0) && pos - 17 == pos_king) {
                    return true;
                }
                break;
        }

        return false;
    }

    private boolean verificarJaqueDiagonal(int[] tablero, int pos, int pos_king) {

        int factor = 1;
        int val;
        boolean a7 = true,
                b7 = true,
                a9 = true,
                b9 = true;
        do {
            if (a7) {
                val = pos - (7 * factor);
                if (val % 8 > 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        a7 = false;
                    }
                } else {
                    a7 = false;
                }
            }
            if (b7) {
                val = pos + (7 * factor);
                if (val < 64 && val % 8 < 7) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        b7 = false;
                    }
                } else {
                    b7 = false;
                }
            }
            if (a9) {
                val = pos - (9 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        a9 = false;
                    }
                } else {
                    a9 = false;
                }
            }
            if (b9) {
                val = pos + (9 * factor);
                if (val < 64 && val % 8 > 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        b9 = false;
                    }
                } else {
                    b9 = false;
                }
            }
            factor++;
        } while ((a7 || b7 || a9 || b9) && factor < 8);

        return false;
    }

    private boolean verificarJaqueHorizontalVertical(int[] tablero, int pos, int pos_king) {

        int factor = 1;
        int val;
        boolean a1 = true,
                b1 = true,
                a8 = true,
                b8 = true;
        do {
            if (a1) {
                val = pos - (1 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        a1 = false;
                    }
                } else {
                    a1 = false;
                }
            }
            if (b1) {
                val = pos + (1 * factor);
                if (val % 8 > 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        b1 = false;
                    }
                } else {
                    b1 = false;
                }
            }
            if (a8) {
                val = pos - (8 * factor);
                if (val >= 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        a8 = false;
                    }
                } else {
                    a8 = false;
                }
            }
            if (b8) {
                val = pos + (8 * factor);
                if (val < 64) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        b8 = false;
                    }
                } else {
                    b8 = false;
                }
            }
            factor++;
        } while ((a1 || b1 || a8 || b8) && factor < 8);

        return false;
    }

    public int[] buscarIndiceAmenazaEscondida(int[][] escondidas, int idx) {
        int temp;

        if (escondidas == null) {
            return null;
        }

        for (int i = 1; i < escondidas[0][indiceMovimiento]; i++) {
            temp = escondidas[i][indiceMovimiento];
            if (temp == idx) {
                return escondidas[i];
            }
        }
        return null;
    }
}
